package gokyesil.game2d.screens;

import gokyesil.game2d.actors.BlockMenu;
import gokyesil.game2d.actors.Blocks;
import gokyesil.game2d.actors.Map;
import gokyesil.game2d.actors.MapBlock;
import gokyesil.game2d.actors.ToolBar;
import gokyesil.game2d.actors.ToolButton;
import gokyesil.game2d.renderer.Assets;

import java.io.Serializable;
import java.util.Iterator;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Buttons;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.Button;
import com.badlogic.gdx.utils.viewport.ScreenViewport;

public class MapEditor extends Stage implements Screen, Serializable
{
	private final static int BLOCK_SIZE = 25; 
	private final int mapX = 125;
	private final int mapY = 25;
	private final int upperInterval = 25;
	private final int rightInterval = 25;
	
	public boolean mainMenu;
	public Vector3 mousePos;
	public boolean isReset;
	public ToolBar toolBar;
	public ToolBar statusBar;
	public BlockMenu blockMenu;
	public ToolButton chainButton;
	public ToolButton camurButton;
	public ToolButton finishButton;
	public ToolButton selectedButton;
	public Map map;
	private boolean deleteMode;
	private boolean play;
	
	public MapEditor() 
	{
		super();
		Gdx.input.setInputProcessor(this);
		mainMenu = false;
		isReset = false;
		deleteMode = false;
		play =false;
		mousePos = new Vector3(0,0,0);
		
		this.addActor(map = new Map(mapX,mapY,this.getWidth()-mapX-rightInterval, this.getHeight()-mapY-upperInterval));
		
		toolBar = new ToolBar(Assets.toolbar,0,0,125,(int)this.getHeight());
		this.addActor(toolBar);
		statusBar = new ToolBar(Assets.toolbar,0,0,(int)this.getWidth(),25);
		this.addActor(statusBar);
		
		toolBar.addActor(blockMenu = new BlockMenu(Assets.brickList,10,25));
		toolBar.addActor(chainButton = new ToolButton(Assets.chain,40,500,40,40));
		toolBar.addActor(finishButton = new ToolButton(Assets.finish,40,300,40,40));
		toolBar.addActor(camurButton = new ToolButton(Assets.camur,40,400,40,40));
		
		
		selectedButton = new ToolButton();
		this.addActor(selectedButton);
	}
		
	public void render(float delta)
	{
		if(play)
			this.act(Gdx.graphics.getDeltaTime());
	    this.draw();
	    if(selectedButton.isVisible())
	    {
	    	mousePos.set(Gdx.input.getX(), Gdx.input.getY(), 0);
			this.getViewport().getCamera().unproject(mousePos);
			selectedButton.setPosition(mousePos.x-selectedButton.getScaleX()*selectedButton.getWidth()/2, mousePos.y-selectedButton.getScaleY()*selectedButton.getHeight()/2);
	    }
		if(deleteMode && !play)
		{
			mousePos.set(Gdx.input.getX(), Gdx.input.getY(), 0);
			this.getViewport().getCamera().unproject(mousePos);
			MapBlock block = (MapBlock) map.hit((mousePos.x-map.getX())/map.getScaleX(), (mousePos.y-map.getY())/map.getScaleY(), true);
			if(block != null)
			{
				map.deleteBlock(block);
			}
		}
	}
	public void resize(int width, int height) 
	{		
		ScreenViewport viewport = new ScreenViewport();
		viewport.update(width,height,true);
		this.setViewport(viewport);
		toolBar.setHeight(height);
		map.resize(width-mapX-rightInterval, height-mapY-upperInterval);
	}
	public boolean keyDown(int key) 
	{
		super.keyDown(key);
		if(key == Keys.ESCAPE)	mainMenu = true;
		if(key == Keys.A) 		map.slideX(true);
		if(key == Keys.D)		map.slideX(false);
		if(key == Keys.W)		map.slideY(false);
		if(key == Keys.S)		map.slideY(true);
		if(key == Keys.G)		map.toggleGridVisibility();
		if(key == Keys.PLUS)	{map.zoom(true);selectedButton.zoom(true);}
		if(key == Keys.MINUS)	{map.zoom(false);selectedButton.zoom(false);}
		if(key == Keys.ALT_LEFT)	deleteMode = true;
		if(key == Keys.P)	toggle();
		if(key == Keys.R)
		{
			isReset = true;
		}
		return false;
	}
	public boolean keyUp(int key) 
	{
		super.keyUp(key);
		if(key == Keys.ALT_LEFT)	deleteMode = false;
		return false;
	}

	public boolean touchDown(int screenX, int screenY, int pointer, int button)
	{
		boolean superReturn = super.touchDown(screenX, screenY, pointer, button);
		mousePos.set(screenX, screenY, 0);
		this.getViewport().getCamera().unproject(mousePos);
		if(button == Buttons.LEFT)
		{
			if(!play)
			{
				if(selectedButton.isVisible())
				{
					if(selectedButton.getStyle() == camurButton.getStyle())
					{
						if(map.addBlock(selectedButton.getStyle(), mousePos.x-map.getX(), mousePos.y-map.getY(),Blocks.Player))
							//selectedButton.setVisible(false);
							return superReturn;
					}
					else if(selectedButton.getStyle() == chainButton.getStyle())
					{
						if(map.addChain(Assets.black, mousePos.x-map.getX(), mousePos.y-map.getY()))
							///selectedButton.setVisible(false);
							return superReturn;
					}
					else if(selectedButton.getStyle() == finishButton.getStyle())
					{
						if(map.addBlock(selectedButton.getStyle(), mousePos.x-map.getX(), mousePos.y-map.getY(),Blocks.Finish))
							//selectedButton.setVisible(false);
							return superReturn;
					}
					else
					{
						if(map.addBlock(selectedButton.getStyle(), mousePos.x-map.getX(), mousePos.y-map.getY(),Blocks.Block))
							return superReturn;
					}

				}
				else
				{
					MapBlock block = (MapBlock) map.hit((mousePos.x-map.getX())/map.getScaleX(), (mousePos.y-map.getY())/map.getScaleY(), true);
					if(block != null)
					{
						selectedButton.set(block.getStyle(),mousePos.x-selectedButton.getWidth()/2, mousePos.y-selectedButton.getHeight()/2,map.getScaleX()); 
						map.deleteBlock(block);
						return superReturn;
					}
				}
			}

			Iterator<Actor> iter = blockMenu.getChildren().iterator();
			while(iter.hasNext())
			{
				Button tempButton = (Button) iter.next();
				if(tempButton.isPressed())
				{
					selectedButton.set(tempButton.getStyle(),mousePos.x-selectedButton.getScaleX()*selectedButton.getWidth()/2, mousePos.y-selectedButton.getScaleY()*selectedButton.getHeight()/2,map.getScaleX()); 
					return superReturn;
				}
			}
			if(camurButton.isPressed())
			{
				selectedButton.set(camurButton.getStyle(),mousePos.x-selectedButton.getScaleX()*selectedButton.getWidth()/2, mousePos.y-selectedButton.getScaleY()*selectedButton.getHeight()/2,map.getScaleX()); 
				return superReturn;
			}
			if(chainButton.isPressed())
			{
				selectedButton.set(chainButton.getStyle(),mousePos.x-selectedButton.getScaleX()*selectedButton.getWidth()/2, mousePos.y-selectedButton.getScaleY()*selectedButton.getHeight()/2,map.getScaleX()); 
				map.removeChain();
				return superReturn;
			}
			if(finishButton.isPressed())
			{
				selectedButton.set(finishButton.getStyle(),mousePos.x-selectedButton.getScaleX()*selectedButton.getWidth()/2, mousePos.y-selectedButton.getScaleY()*selectedButton.getHeight()/2,map.getScaleX()); 
				return superReturn;
			}
		}
		if(button == Buttons.RIGHT)
		{
			if(selectedButton.isVisible())
			{
				selectedButton.setVisible(false);
				return superReturn;
			}
			else
			{
				deleteMode = true;
				if(!play)
				{
					MapBlock block = (MapBlock) map.hit((mousePos.x-map.getX())/map.getScaleX(), (mousePos.y-map.getY())/map.getScaleY(), true);
					if(block != null)
					{
						map.deleteBlock(block);
						return superReturn;
					}
				}
			}
		}
		
		return superReturn;
	}
	/*public boolean mouseMoved(int screenX, int screenY) 
	{
		boolean superReturn = super.mouseMoved(screenX, screenY);


		return superReturn;
	}*/
	public boolean touchDragged (int screenX, int screenY, int pointer)
	{
		boolean superReturn = super.touchDragged(screenX, screenY, pointer);
		if(!play)
		{
		    if(selectedButton.isVisible())
		    {
				if(selectedButton.getStyle() != camurButton.getStyle() && selectedButton.getStyle() != chainButton.getStyle() && selectedButton.getStyle() != finishButton.getStyle())
				{
					mousePos.set(screenX, screenY, 0);
					this.getViewport().getCamera().unproject(mousePos);
					selectedButton.setPosition(mousePos.x-selectedButton.getWidth()/2, mousePos.y-selectedButton.getHeight()/2);
					if(map.addBlock(selectedButton.getStyle(), mousePos.x-map.getX(), mousePos.y-map.getY(),Blocks.Block))
						return superReturn;
				}
		    }
		}

		return superReturn;
	}
	public boolean touchUp(int screenX, int screenY, int pointer, int button)
	{
		if(button == Buttons.RIGHT) 
			deleteMode = false;
		return super.touchUp(screenX, screenY, pointer, button);	
	}
	/*public boolean touchUp(int screenX, int screenY, int pointer, int button)
	{
		boolean superReturn = super.touchUp(screenX, screenY, pointer, button);
	    if(button == Input.Buttons.LEFT)
	    	isLeftMouseDragging = false;
	    if(button == Input.Buttons.RIGHT)
	    	isRightMouseDragging = false;
	    if(button == Input.Buttons.MIDDLE && isMiddleMouseDragging)
	    {
	    	isMiddleMouseDragging = false;
	    	Vector2 velocity = new Vector2(mouseMidIn.x-mousePos.x,mouseMidIn.y-mousePos.y);
	    	sicimlik.getBody().setLinearVelocity(velocity.scl(0.2f));
	    }
	    
	    if(playButton.isChecked())
 		{
 	    	play = true;
 		}
 	    else
 	    {
 	    	play = false;
 	    }
 	    Iterator<Actor> iter = blockMenu.getChildren().iterator();
 	    while(iter.hasNext())
 	    {
 	    	Button tempButton = (Button) iter.next();
 	    	if(tempButton.isPressed())
 	    	{
 	    		isSelected = true;
 	    		selectedButton.setStyle(tempButton.getStyle());
 	    		selectedButton.setWidth(tempButton.getWidth());
 	    		selectedButton.setHeight(tempButton.getHeight());
 	    	}
 	    }
 	    if(camurButton.isPressed())
 		{
    		selectedButton.setStyle(camurButton.getStyle());
    		selectedButton.setWidth(camurButton.getWidth());
    		selectedButton.setHeight(camurButton.getHeight());
 		}
 	    if(finishButton.isPressed())
 		{
    		selectedButton.setStyle(finishButton.getStyle());
    		selectedButton.setWidth(finishButton.getWidth());
    		selectedButton.setHeight(finishButton.getHeight());
 		}
 	    
 	    iter = map2.getChildren().iterator();
 	    while(iter.hasNext())
 	    {
 	    	MapBlock block = (MapBlock) iter.next();
 	    	if(block.isPressed())
 	    	{
 	    		isSelected = true;
 	    		selectedButton.setStyle(block.getStyle());
 	    		selectedButton.setWidth(block.getWidth());
 	    		selectedButton.setHeight(block.getHeight());
 	    		map2.deleteBlock(block);
 	    	}
 	    }
 	    
		return superReturn;
	}
	
	public boolean touchDragged (int screenX, int screenY, int pointer)
	{
		boolean superReturn = super.touchDragged(screenX, screenY, pointer);
		Vector3 mousePos = new Vector3(screenX,screenY,0);
		this.getViewport().getCamera().unproject(mousePos);
		
		Iterator<Actor>iter = map2.getChildren().iterator();
		boolean isPressed = false;
 	    while(iter.hasNext())
 	    {
 	    	MapBlock block = (MapBlock) iter.next();
 	    	if(block.isOver())
 	    	{
 	    		isPressed = true;
 	    		break;
 	    	}
 	    }
		if(!isPressed && isSelected)
		{
	    	//float newBlockSize = BLOCK_SIZE*map2.getScaleX();
	    	//float newX = ((int)((mousePos.x-map2.getX())/newBlockSize))*BLOCK_SIZE;
	    	//float newY = ((int)((mousePos.y-map2.getY())/newBlockSize))*BLOCK_SIZE;
	    	float newX = (mousePos.x-map2.getX())/map2.getScaleX();
	    	float newY = (mousePos.y-map2.getY())/map2.getScaleY();
	    	map2.addBlock(selectedButton.getStyle(), newX, newY);
		}
		return superReturn;
	}*/
	
/*	public void chain()
	{
//		this.addActor(new Block (texture, x, y, 0.6f, 0.125f, 0, physWorld));
//	      PolygonShape shape = new PolygonShape();
//	      shape.setAsBox(0.6f, 0.125f);
//
//	      FixtureDef fd = new FixtureDef();
//	      fd.shape = shape;
//	      fd.density = 20.0f;
//	      fd.friction = 0.2f;
		  isChain = true;

		  
		 
		  /*for(int i=0; i<3; i++)
		  {
			  //Block block = new Block(Assets.brick2, i*25+50, 300, BLOCK_SIZE, BLOCK_SIZE, 0, physWorld);
			  map.addBlock(Assets.brick2, i*25+100, 300, physWorld);
		  }*/
		 /* this.addActor(new Block (Assets.brick2, 50, 300, BLOCK_SIZE, BLOCK_SIZE, 0, physWorld));
		  this.addActor(new Block (Assets.brick2, 75, 300, BLOCK_SIZE, BLOCK_SIZE, 0, physWorld));
		  chain.addActor(new Block (Assets.brick2, 100, 300, BLOCK_SIZE, BLOCK_SIZE, 0, physWorld));
		  chain.addActor(new Block (Assets.brick2, 125, 300, BLOCK_SIZE, BLOCK_SIZE, 0, physWorld));
		  chain.addActor(new Block (Assets.brick2, 150, 300, BLOCK_SIZE, BLOCK_SIZE, 0, physWorld));
		  chain.addActor(new Block (Assets.brick2, 175, 300, BLOCK_SIZE, BLOCK_SIZE, 0, physWorld));
		  chain.addActor(new Block (Assets.brick2, 200, 300, BLOCK_SIZE, BLOCK_SIZE, 0, physWorld));*/
//		  this.addActor(new Block (Assets.brick2, 225, 300, BLOCK_SIZE, BLOCK_SIZE, 0, physWorld));
	    /*  RevoluteJointDef jd = new RevoluteJointDef();
	      jd.collideConnected = false;
	      

	      final float y = 400f;
	      prevBlock =  map.addChain(Assets.brick1, 400, y, 20, 5, physWorld);
	      Block stone = map.addBlock(Assets.brick2, 400, y, physWorld);
	      jd.initialize(prevBlock.getBody(), stone.getBody(), prevBlock.getBody().getPosition());
	      physWorld.createJoint(jd);
	      chain = new Block[20];
	      chain[0] = prevBlock;
	      for (int i = 1; i < 20; i++) 
	      {
//	        BodyDef bd = new BodyDef();
//	        bd.type = BodyType.DYNAMIC;
//	        bd.position.set(0.5f + i, y);
//	        Body body = getWorld().createBody(bd);
//	        body.createFixture(fd);
	    	Block block = map.addChain(Assets.brick1, i*10+400, y, 20, 5, physWorld);
			  
			chain[i]=block;

	        Vector2 anchor = new Vector2((prevBlock.getBody().getPosition().x+block.getBody().getPosition().x)/2.0f, (prevBlock.getBody().getPosition().y+block.getBody().getPosition().y)/2.0f);
	        jd.initialize(prevBlock.getBody(), block.getBody(), anchor);
	        jd.enableMotor = true;
	        jd.enableLimit = true;
	        jd.collideConnected = true;
	        jd.upperAngle = MathUtils.PI/9.0f;
	        jd.lowerAngle = -MathUtils.PI/9.0f;
	        physWorld.createJoint(jd);
	        //this.addActor(prevBlock);
	        prevBlock = block;
	      }
	   
	 }
	public void rope()
	{
		RopeJointDef ropeJointDef= new RopeJointDef();
//		Block b2 = new Block(Assets.brick2, sicimlik.getX()+((sicimlik.getBody().getLinearVelocity().x > 0) ? 50 : -50), sicimlik.getY()+100,25,25,0,physWorld);
		Block b2 = new Block(Assets.brick2, sicimlik.getX()+50, sicimlik.getY()+100,25,25,0,physWorld);
		ropeTarget.set(b2.getBody().getPosition().scl(5));
		isThereRope = true;
		map.addActor(b2);;
		ropeJointDef.bodyA = sicimlik.getBody();
		ropeJointDef.bodyB = b2.getBody();
		ropeJointDef.localAnchorA.set(0,0);
		ropeJointDef.localAnchorB.set(0,0);
		ropeJointDef.maxLength = 20;
		ropeJointDef.collideConnected = true;
		joint = physWorld.createJoint(ropeJointDef);
		
	}
	public void rope2()
	{
		RopeJointDef ropeJointDef= new RopeJointDef();
		ropeCallBack.isHit = false;
		
//		//Raycast
//		RayCastInput input;
//		physWorld.r
		physWorld.rayCast(ropeCallBack,sicimlik.getBody().getPosition(), new Vector2(sicimlik.getBody().getPosition().x+((sicimlik.getBody().getLinearVelocity().x > 0) ? 15 : -15), sicimlik.getBody().getPosition().y+30));
		if(!ropeCallBack.isHit)
			return;
		
		ropeTarget.set(ropeCallBack.body.getPosition().x*5,ropeCallBack.body.getPosition().y*5);
		isThereRope = true;
		ropeJointDef.bodyA = sicimlik.getBody();
		ropeJointDef.bodyB = ropeCallBack.body;
		ropeJointDef.localAnchorA.set(0,0);
		float length = ropeCallBack.point.dst(sicimlik.getBody().getPosition());
		ropeJointDef.localAnchorB.set(ropeCallBack.point.sub(ropeCallBack.body.getPosition()));
		
		
		
		ropeJointDef.maxLength = length;
		ropeJointDef.collideConnected = true;
		joint = physWorld.createJoint(ropeJointDef);
	}
	/*public MapSaveImage save()
	{
		Actor[] actorArray = map.getChildren().toArray(); // NOT EFFICIENT
		ArrayList<BlockSaveImage> blockList = new ArrayList<BlockSaveImage>();
		for(int i=0; i<actorArray.length; i++)
			if(actorArray[i] instanceof Block)
				blockList.add(((Block)actorArray[i]).getSaveImage());
		MapSaveImage saveImage = new MapSaveImage();
		saveImage.blockList = blockList;
		saveImage.map = map.map;
		return saveImage;
	}
	
	public void load(MapSaveImage saveImage)
	{
		map.delete();
		ArrayList<BlockSaveImage> blockList = saveImage.blockList; 
		for(int i=0; i<blockList.size(); i++)
			map.addActor(new Block(blockList.get(i),physWorld));
		map.map=saveImage.map;
	}
	**/
	
	@Override
	public void dispose() {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void hide() {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void pause() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void resume() {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void show() {
		// TODO Auto-generated method stub
		Gdx.input.setInputProcessor(this);
	}
	public void toggle()
	{
		if(play)
			map.reset();
		else
			map.getClones();
		play = !play;
	}
}

/*if(isChain)
{
	Vector2 points[] = new Vector2[20];
	for(int i=0; i<20; i++) 
	{
		points[i] = chain[i].getWindowPosition().add(mapX, mapY);
		//System.out.println(points[i].toString());
	}
		
	Vector2 p0 = new Vector2();
	Vector2 p1 = new Vector2();
	Vector2 p2 = new Vector2();
	BSpline<Vector2> spline = new BSpline<Vector2>(points, 3, false);
	
	float val=0.00f;
	spline.valueAt(/* out: *//*p0, val);
	shapeRenderer.setColor(0f, 0f, 0f, 1f);
	shapeRenderer.begin(ShapeType.Filled);
	while (val < 0.989f) {
		spline.valueAt(/* out: *//*p1, val);
		spline.valueAt(/* out: *//*p2, val+0.01f);
		shapeRenderer.rect(p1.x, p1.y, p2.dst2(p1), 5, (p2.y-p1.y)/2.0f, (p2.y-p1.y)/2.0f,1,1, p2.sub(p1).angle());
		//shapeRenderer.rect(p1.x, p1.y, p2.dst2(p1), 10);
		//shapeRenderer.rect(p1.x+val*100, p1.y+val*100, (p2.x-p1.x)*5, 10, p1.x+val*100, p1.y+val*100, p2.sub(p1).angle());
		val += 0.01f;
	}
	shapeRenderer.end();
}*/
